<template>
  <div>
    <!-- 主容器使用 Element UI 的布局组件 -->
    <el-container>
      <!-- 头部区域 -->
      <el-header class="header" style="padding:0px">
        <!-- 返回按钮 -->
        <i class="el-icon-back back" @click="goBack"></i>
        <!-- 标题，显示当前车型和系统名称 -->
        <span class="title">{{ typeTit }}故障模型及诊断方法系统</span>
      </el-header>
      
      <!-- 主内容区域 -->
      <el-main style="padding:0px">
        <el-row>
          <el-col :span="24">
            <!-- GoJS 图表容器 -->
            <div id="container" ref="test" :style="{ height: height + 'px' }"></div>
          </el-col>
        </el-row>
      </el-main>
    </el-container>
    
    <!-- 故障解决方法弹窗 -->
    <el-dialog v-model="dialogVisible" width="50%">
      <!-- 弹窗标题 -->
      <template #header>
        <div style="font-size:20px; color:#303133; font-weight:bold">
          {{ fauTitle }}
        </div>
      </template>

      <!-- 弹窗内容 -->
      <div class="fauSolShow">
        <!-- 故障图片，如果有的话 -->
        <el-image fit="fill" class="fauImg" :src="img64" :preview-src-list="[img64]" v-show="showImg" />
        <!-- 故障解决方案描述 -->
        <div class="solDes">{{ solution }}</div>
      </div>

      <!-- 弹窗底部按钮 -->
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogClose">取 消</el-button>
          <el-button type="primary" @click="dialogClose">确 定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import go from 'gojs'  // 引入 GoJS 图表库
// eslint-disable-next-line no-unused-vars
import { andGate, orGate } from '../shape/shape'  // 引入自定义的逻辑门形状
const $ = go.GraphObject.make  // GoJS 的快捷创建方法

export default {
  name: 'FaultTreeDiagram',  // 组件名称，建议使用有意义的名称
  
  data() {
    return {
      height: '',  // 容器高度
      myDiagram: null,  // GoJS 图表实例
      nodeDataArray: [],  // 存储节点数据
      uuid: '',  // 当前故障UUID
      faultTitle: '',  // 故障标题
      dialogVisible: false,  // 控制解决方案弹窗显示
      solution: '',  // 故障解决方案文本
      fauTitle: '',  // 弹窗标题
      img64: '',  // 故障图片的base64数据
      showImg: false,  // 是否显示故障图片
      typeTit: ''  // 车型标题
    }
  },
  
  methods: {
    /**
     * 返回上一页
     */
    goBack() {
      this.$router.go(-1)
    },
    
    /**
     * 关闭解决方案弹窗并重置相关数据
     */
    dialogClose() {
      this.dialogVisible = false
      this.solution = ''
      this.img64 = ''
      this.showImg = false
    },
    
    /**
     * 根据逻辑门类型返回对应的填充颜色
     * @param {string} figure - 逻辑门类型 ('AndGate' 或 'OrGate')
     * @return {string} 对应的颜色值
     */
    nodeFillConverter(figure) {
      switch (figure) {
        case 'AndGate':
          return '#ff681a'  // 与门颜色
        case 'OrGate':
          return '#00b3ad'  // 或门颜色
        default:
          return 'whitesmoke'  // 默认颜色
      }
    },
    
    /**
     * 根据节点类型返回对应的尺寸
     * @param {boolean} figure - 是否基础节点
     * @return {go.Size} 节点尺寸对象
     */
    nodeWidth(figure) {
      return figure 
        ? new go.Size(190, 190)  // 基础节点尺寸
        : new go.Size(220, 90)   // 非基础节点尺寸
    },
    
    /**
     * 根据节点类型返回文本宽度
     * @param {object} f - 节点数据对象
     * @return {number} 文本宽度
     */
    test(f) {
      return f.base ? 133 : 170  // 基础节点和非基础节点的文本宽度
    },
    
    /**
     * 初始化 GoJS 图表
     */
    init() {
      // 创建图表实例
      this.myDiagram = $(go.Diagram, 'container', {
        allowCopy: false,
        allowDelete: false,
        'draggingTool.dragsTree': true,  // 允许拖动整个树
        layout: $(go.TreeLayout, { angle: 90, layerSpacing: 30 }),  // 树形布局，垂直方向
        'undoManager.isEnabled': true,  // 启用撤销管理
        contentAlignment: go.Spot.Center,  // 内容居中
        'toolManager.mouseWheelBehavior': go.ToolManager.WheelZoom  // 鼠标滚轮缩放
      })

      // 定义节点模板
      this.myDiagram.nodeTemplate = $(
        go.Node, 'Spot',
        { 
          selectionObjectName: 'BODY', 
          locationSpot: go.Spot.Center, 
          locationObjectName: 'BODY', 
          selectionAdorned: false, 
          isTreeExpanded: false 
        },
        // 节点主体部分
        $(go.Panel, 'Auto', { name: 'BODY', portId: '' },
          $(go.Shape,
            // 绑定节点形状和大小
            new go.Binding('figure', 'base', (f) => f ? 'Circle' : 'Rectangle'),
            new go.Binding('desiredSize', 'base', this.nodeWidth),
            { fill: '#662400', stroke: null }  // 节点填充颜色
          ),
          $(go.TextBlock,
            new go.Binding('width', this.test),  // 绑定文本宽度
            {
              minSize: new go.Size(0, NaN),
              stroke: 'whitesmoke',  // 文本颜色
              font: '16pt Segoe UI, sans-serif',  // 字体样式
              isMultiline: true,  // 允许多行文本
              overflow: go.TextBlock.OverflowEllipsis,  // 溢出显示省略号
              maxLines: 3,  // 最大行数
              textAlign: 'center'  // 文本居中
            },
            new go.Binding('text')  // 绑定文本内容
          )
        ),
        { click: this.NodeClick, cursor: 'pointer' },  // 节点点击事件
        
        // 树形展开/折叠按钮
        $('TreeExpanderButton', {
          name: 'TREEBUTTON',
          alignment: go.Spot.Right,
          alignmentFocus: go.Spot.Left,
          'ButtonBorder.figure': 'Rectangle',
          click: (e, obj) => {
            const node = obj.part
            if (node === null) return
            e.handled = true
            this.expandNode(node)
          }
        }),
        
        // 节点下方的连接线
        $(go.Shape, 'LineV',
          new go.Binding('visible', 'figure', f => f !== 'None'),
          { strokeWidth: 1.5, height: 20, alignment: new go.Spot(0.5, 1, 0, -1), alignmentFocus: go.Spot.Top }
        ),
        
        // 逻辑门形状
        $(go.Shape,
          new go.Binding('visible', 'figure', f => f !== 'None'),
          {
            alignment: new go.Spot(0.5, 1, 0, 5),
            alignmentFocus: go.Spot.Top,
            width: 40,
            height: 40,
            stroke: null
          },
          new go.Binding('figure'),  // 绑定形状类型
          new go.Binding('fill', 'figure', this.nodeFillConverter),  // 绑定填充颜色
          new go.Binding('angle', 'figure', f => (f === 'OrGate' || f === 'AndGate') ? -90 : 0)  // 逻辑门旋转角度
        )
      )
      
      // 定义连接线模板
      this.myDiagram.linkTemplate = $(
        go.Link, go.Link.Orthogonal,
        { layerName: 'Background', curviness: 20, corner: 5 },
        $(go.Shape, { strokeWidth: 1.5 }),  // 连接线样式
        $(go.Shape, { toArrow: 'Standard' })  // 箭头样式
      )
      
      // 初始布局完成后自动展开前两级
      this.myDiagram.addDiagramListener('InitialLayoutCompleted', e => {
        e.diagram.findTreeRoots().each(r => r.expandTree(2))
      })
      
      // 设置图表模型数据
      this.myDiagram.model = new go.TreeModel(this.nodeDataArray)
    },

    /**
     * 展开或折叠节点
     * @param {go.Node} node - 要展开/折叠的节点
     */
    expandNode(node) {
      const diagram = this.myDiagram
      diagram.startTransaction('CollapseExpandTree')  // 开始事务
      if (node.isTreeExpanded) {
        diagram.commandHandler.collapseTree(node)  // 折叠节点
      } else {
        diagram.commandHandler.expandTree(node)  // 展开节点
      }
      diagram.commitTransaction('CollapseExpandTree')  // 提交事务
      this.myDiagram.zoomToFit()  // 自适应缩放
    },
    
    /**
     * 获取故障树数据
     */
    async getTree() {
      this.uuid = this.$route.params.uuid  // 从路由参数获取UUID
      const res = await this.$api.post('/getNextFault', this.uuid)  // 请求子故障数据
      
      // 处理返回数据，构建节点数组
      const testArr = res.data.map((a) => ({
        key: a.uuid,
        text: a.pheno,
        figure: a.figure,
        parent: a.fatherUnid,
        base: a.baseEvent
      })).slice(1)  // 跳过第一个元素
      
      // 添加根节点
      const a = res.data[0]
      testArr.unshift({ 
        key: a.uuid, 
        text: a.pheno, 
        figure: a.figure, 
        base: a.baseEvent 
      })
      
      this.nodeDataArray = testArr  // 更新节点数据
    },
    
    /**
     * 获取故障解决方案
     * @param {string} faultTitle - 故障标题/ID
     */
    async getReslove(faultTitle) {
      const res = await this.$api.post('/getResolvent', faultTitle)
      this.showImg = res.data.img !== null  // 根据是否有图片设置显示状态
      
      // 处理解决方案文本，转换换行符
      const sol = String(res.data.solution).replace(/\\n/g, '\n')
      this.solution = res.data ? sol : '问题解决方案'
      
      // 如果有图片，转换为base64格式
      this.img64 = this.getBase64(res.data.img)
    },
    
    /**
     * 将图片数据转换为base64格式
     * @param {string} base64 - 图片的base64数据
     * @return {string} 完整的base64图片URL
     */
    getBase64(base64) {
      return base64 ? 'data:image/png;base64,' + base64 : ''
    },
    
    /**
     * 节点点击事件处理
     * @param {MouseEvent} e - 鼠标事件
     * @param {go.Node} node - 被点击的节点
     */
    NodeClick(e, node) {
      if (node.data.base) {  // 只有基础节点才显示解决方案
        this.dialogVisible = true
        this.fauTitle = node.data.text
        this.getReslove(node.data.key)  // 获取解决方案
      }
    },
    
    /**
     * 计算并设置容器高度
     */
    getHeight() {
      this.height = window.innerHeight - 60  // 窗口高度减去头部高度
    }
  },
  
  // 生命周期钩子
  mounted() {
    this.getHeight()  // 初始化高度
    window.addEventListener('resize', this.getHeight)  // 监听窗口大小变化
    
    // 延迟初始化图表，确保DOM已渲染
    setTimeout(() => {
      this.init()
    }, 120)
    
    this.typeTit = localStorage.getItem('type')  // 从本地存储获取车型
  },
  
  unmounted() {
    // 组件销毁时移除事件监听
    window.removeEventListener('resize', this.getHeight)
  },
  
  created() {
    this.getTree()  // 创建时获取故障树数据
  }
}
</script>

<style scoped lang='scss'>
/* 图表容器样式 */
#container {
  width: 100%;
  opacity: 1;

  /* 背景图片 */
  &::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background: url('../assets/111.jpg') no-repeat;
    background-position: center;
    background-size: cover;
    opacity: .6;  // 半透明背景
  }
}

/* 头部样式 */
.header {
  background-color: #409eff;  // Element UI 主色
  color: #fff;
  text-align: center;
  line-height: 60px;
  font-size: 26px;

  /* 返回按钮样式 */
  .back {
    line-height: 60px;
    float: left;
    cursor: pointer;
    margin-left: 16px;
  }

  .title {
    margin-right: 35px;
  }
}

/* 解决方案弹窗内容样式 */
.fauSolShow {
  display: flex;
  flex-direction: column;
  justify-content: center;

  /* 故障图片样式 */
  .fauImg {
    width: 300px;
    height: 300px;
    flex: 1;
    margin: auto;
  }

  /* 解决方案文本样式 */
  .solDes {
    margin-top: 2rem;
    font-size: 1.5rem;
    white-space: pre-wrap;  // 保留换行和空格
    letter-spacing: 2px;  // 字间距
  }
}
</style>